﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using Effects.Effects;
using Effects.Effects.GuiParts;

namespace EffectsPack
{

    /// <summary>
    ///  Touchpad controls. Allows user to control two parameters.
    /// </summary>
    /// <remarks>
    ///  Control reacts on user pressing the mouse button and then moving the mouse (while button down). It raises two different events
    ///  for mouse position change in both axis. Both width and depth is mapped to [0;1] interval.
    /// </remarks>
    public partial class Pad : UserControl
    {
        #region constructor

        /// <summary>
        ///  Creates new instance.
        /// </summary>
        public Pad()
        {
            BackColor = Color.Transparent;
            InitializeComponent();
            foreBrush = System.Drawing.Brushes.Blue;
            Render();
        }

        #endregion

        #region mouse_events

        /// <summary>
        ///  Indicates mouse button is down.
        /// </summary>
        private bool mouseDown;

        /// <summary>
        ///  Sets mouseDown to true.
        /// </summary>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            mouseDown = true;
        }

        /// <summary>
        ///  Sets mouseUp to false.
        /// </summary>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            mouseDown = false;
        }

        /// <summary>
        ///  Reacts on mouse move.
        /// </summary>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (mouseDown)
            {
                if (e.X >= 0 && e.X <= Width)
                {
                    double val = (double)e.X / (double)this.Width;
                    PotValueChangedEventArgs argsH = new PotValueChangedEventArgs(val);
                    if (this.HorizontalValueChanged != null)
                        HorizontalValueChanged(this, argsH);
                }

                if (e.Y >= 0 && e.Y <= Height)
                {
                    double val = (double)e.Y / (double)Height;
                    PotValueChangedEventArgs argsV = new PotValueChangedEventArgs(val);
                    if (this.VerticalValueChanged != null)
                        VerticalValueChanged(this, argsV);
                }
            }
        }

        /// <summary>
        ///  Raised when user moves in horizontal direction.
        /// </summary>
        public event PotValueChangedEventHandler HorizontalValueChanged;

        /// <summary>
        ///  Raised when user moves in vertical direction.
        /// </summary>
        public event PotValueChangedEventHandler VerticalValueChanged;
        #endregion

        #region painting

        /// <summary>
        ///  Brush to paint the pad.
        /// </summary>
        private Brush foreBrush;

        /// <summary>
        ///  Foreground brush
        /// </summary>
        public Brush ForegroundBrush
        {
            get { return foreBrush; }
            set 
            { 
                foreBrush = value;
                Render();
                Refresh();
            }
        }

        /// <summary>
        ///  Image for double buffering the control.
        /// </summary>
        Image doubleBuffer;

        /// <summary>
        ///  Renders the image to the doubleBuffer.
        /// </summary>
        private void Render()
        {
            Bitmap newImage = new Bitmap(Width, Height);
            Graphics g = Graphics.FromImage(newImage);
            g.FillRectangle(foreBrush, 2, 2, Width - 4 , Height - 4);

            Pen p = new Pen(Color.Black, 3);
            DrawRoundRect(g, p, 1, 1, Width - 3, Height - 3, 5);

            doubleBuffer = newImage;
        }
        
        /// <summary>
        ///  Draws rounded rectangle using given Graphics.
        /// </summary>
        /// <param name="g"> Graphics used to draw. </param>
        /// <param name="p"> Pen to draw the rectangle. </param>
        /// <param name="x"> Upper right x-coordinate </param>
        /// <param name="y"> Upper right y-coordinate </param>
        /// <param name="width"> Widht of rectnagle </param>
        /// <param name="height"> Height of rectangle </param>
        /// <param name="radius"> Radius of rounded corners </param>
        public void DrawRoundRect(Graphics g, Pen p, int x, int y, int width, int height, int radius)
        {
            GraphicsPath gp = new GraphicsPath();

            gp.AddLine(x + radius, y, x + width - (radius * 2), y); // Line
            gp.AddArc(x + width - (radius * 2), y, radius * 2, radius * 2, 270, 90); // Corner
            gp.AddLine(x + width, y + radius, x + width, y + height - (radius * 2)); // Line
            gp.AddArc(x + width - (radius * 2), y + height - (radius * 2), radius * 2, radius * 2, 0, 90); // Corner
            gp.AddLine(x + width - (radius * 2), y + height, x + radius, y + height); // Line
            gp.AddArc(x, y + height - (radius * 2), radius * 2, radius * 2, 90, 90); // Corner
            gp.AddLine(x, y + height - (radius * 2), x, y + radius); // Line
            gp.AddArc(x, y, radius * 2, radius * 2, 180, 90); // Corner
            gp.CloseFigure();

            g.DrawPath(p, gp);
            gp.Dispose();
        }

        /// <summary>
        ///  Displays double buffer.
        /// </summary>
        /// <param name="e"> Painting event arguments. </param>
        protected override void OnPaint(PaintEventArgs e)
        {
            try
            {
                Graphics g = e.Graphics;
                g.DrawImage(doubleBuffer, 0, 0);
            }
            catch (Exception)
            {
                Render();
                Refresh();
            }
        }

        /// <summary>
        ///  Forces to render new double buffer.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            Render();
        }

        #endregion
    }
}
